<template>
  <form
    :action="action"
    :method="method"
    :target="target"
    :name="name"
    :autocomplete="autocomplete"
    :enctype="enctype"
    :novalidate="novalidate"
    ref="form"
  >
    <slot></slot>
  </form>
</template>

<script>
  import validateOutside from './methods/validate.js'
  import validateFieldOutside from './methods/validateField.js'

  const listenerEventList = ['input', 'blur', 'change', 'focus'] // 监听事件列表

  export default {
    name: 'XForm',
    props: {
      // 自定义属性
      model: {
        type: Object,
        default: () => ({}),
      },

      rules: {
        type: Object,
        default: () => ({}),
      },
      // 表单默认属性
      action: {
        type: String,
        default: '',
      },
      method: {
        type: String,
        default: 'GET',
      },
      target: {
        type: String,
        default: '_self',
      },
      name: {
        type: String,
        default: '',
      },
      autocomplete: {
        type: String,
        default: 'on',
      },
      enctype: {
        type: String,
        default: 'application/x-www-form-urlencoded',
      },

      novalidate: {
        type: Boolean,
        default: false,
      },
    },
    methods: {
      // 验证整个表单
      validate(callback) {
        const validData = validateOutside(this.model, this.rules)
        console.log(validData.valid)
        callback(validData.valid)

        // 将每个字段的校验结果交给input组件
        const validKeys = Object.keys(validData)
        validKeys.forEach(key => {
          this.$children.forEach(child => {
            if (child.prop === key) {
              const inputInstance = child.$children[0]
              // 遍历prop中第一个不为空的校验结果作为错误信息
              const errorArr = validData[key].filter(item => item)
              if (errorArr.length > 0) inputInstance.error = errorArr[0]
            }
          })
        })
      },
      // 验证单个字段
      validateField(prop, callback) {
        let errorArr = []
        this.rules[prop].forEach(rule => {
          const valid = validateFieldOutside(this.model[prop], rule)
          errorArr.push(valid)
        })
        // 过滤空值
        errorArr = errorArr.filter(item => item)
        // 调用回调函数，将校验结果返回
        if (errorArr.length > 0) {
          // 将错误信息发送给input组件
          const xFormItemInstance = this.$children.find(child => child.prop === prop) //获取x-form-item组件实例
          const inputInstance = xFormItemInstance.$children[0] // 获取input组件实例
          inputInstance.error = errorArr[0] // 设置错误信息
          callback && callback(errorArr[0])
        } else {
          callback && callback(true)
        }
      },
      // 重置表单
      resetFields() {},
      // 清楚校验结果
      clearValidate() {},
    },
    mounted() {
      // 将组件加载完毕时，遍历rules中的每个字段，再遍历字段中的规则，如果规则中存在toggle属性，则开启对应的监听
      const rulesKeys = Object.keys(this.rules) // 获取rules中所有的字段
      rulesKeys.forEach(key => {
        const ruleArr = this.rules[key] // 获取当前字段的规则数组
        ruleArr.forEach(rule => {
          if (rule.trigger) {
            // 如果存在toggle属性，则开启监听
            const xFormItemInstance = this.$children.find(child => child.prop === key) //获取x-form-item组件实例
            const inputInstance = xFormItemInstance.$children[0] // 获取input组件实例
            if (!listenerEventList.includes(rule.trigger)) throw new Error('trigger属性值错误')
            inputInstance.oppenLisener(rule.trigger, this.validateField.bind(this, key, null)) // 开启监听
          }
        })
      })
    },
  }
</script>

<style lang="scss" scoped></style>
